Repository navigation
Blocked BitPacked: decode blocked bitwidths - #10202
Conversation
6ada699 to
e780ee8
Compare
Merging this PR will regress 1 benchmark
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | WallTime | bitpack_blocked_compress_avx512 |
4.9 µs | 5.6 µs | -13.45% |
| ⚡ | WallTime | threshold_neon[8] |
4 µs | 2.9 µs | +37.2% |
| ⚡ | WallTime | threshold_neon[80] |
5.8 µs | 4.9 µs | +18.51% |
| ⚡ | WallTime | threshold_neon[64] |
5.3 µs | 4.5 µs | +18.17% |
| ⚡ | WallTime | filter_neon[64] |
3.5 µs | 3 µs | +16.09% |
| ⚡ | WallTime | bitpack_blocked_compress_avx2 |
7.6 µs | 6.8 µs | +12.16% |
| ⚡ | WallTime | filter_neon[80] |
3.5 µs | 3.2 µs | +10.24% |
| 🆕 | WallTime | bitpack_blocked_decompress_avx512[u32] |
N/A | 9.4 µs | N/A |
| 🆕 | WallTime | bitpack_blocked_decompress_avx512[u64] |
N/A | 18.7 µs | N/A |
| 🆕 | WallTime | bitpack_blocked_decompress_avx2[u32] |
N/A | 10.8 µs | N/A |
| 🆕 | WallTime | bitpack_blocked_decompress_avx2[u64] |
N/A | 21.2 µs | N/A |
| 🆕 | WallTime | bitpack_blocked_decompress_neon[u32] |
N/A | 13.9 µs | N/A |
| 🆕 | WallTime | bitpack_blocked_decompress_neon[u64] |
N/A | 30 µs | N/A |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing mk/bitpacked-variable-decode (d2a6f7e) with develop (9d5a844)
957cefe to
67da367
Compare
b6f53eb to
c70f089
Compare
760be2a to
656dea8
Compare
656dea8 to
0fdbb09
Compare
|
|
||
| decode_blocks(array, &offsets, uninit_slice); | ||
|
|
||
| if let Some(patches) = array.patches() { | ||
| apply_patches_to_uninit_range(&mut uninit_range, &patches, ctx, |v: T| v)?; | ||
| } |
There was a problem hiding this comment.
you want overlap patches and blocks
There was a problem hiding this comment.
this is what global does as well, can have as a followup pr
There was a problem hiding this comment.
sure but todo for now?
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
75fe6ef to
d2a6f7e
Compare
Tracking Issue: #10167 ## Summary Adds a wire format for `BitPacked` arrays whose blocks each have their own bit width, and makes it the in-memory ID, following `fastlanes.for.v2` (#10135) and `DecimalByteParts`. | ID | Role | |---|---| | `fastlanes.bitpacked` | Frozen wire format for global-width arrays. Unchanged. | | `fastlanes.bitpacked.v2` | In-memory ID, and the wire format for per-block bit widths. | `BitPackedPlugin` declares both serialized IDs and picks one per array from `bit_widths()`: - **Global width** writes `fastlanes.bitpacked` exactly as before. Existing files read as before, and default writes stay byte-identical. - **Blocked** writes `fastlanes.bitpacked.v2`. The plugin moves into `bitpacking/plugin/`, laid out like FoR's: `mod.rs` holds the IDs and the dispatch, `v1.rs` the v1 metadata and serde, `v2.rs` the new format, and `tests.rs` the existing tests plus new ones. The v1 code is moved unchanged, except that it writes `bitpacked_v1_id()` rather than the plugin's ID. ## `fastlanes.bitpacked.v2` layout - **Buffers**: the packed buffer, as in v1. - **Children**: v1's children (patch indices, values and chunk offsets, then validity), followed by the block offsets. The block offsets are serialized like any other child, so the compressor can compress them. - **Metadata**: a prost message holding `offset`, the block offsets' unsigned `PType`, and the patches metadata. There is no bit width, and the block offsets' length, `ceil((offset + len) / 1024) + 1`, is derived. Deserialization checks for one buffer and the expected number of children, and validates the offset before deriving the block offsets' length. Construction then checks the block offsets' dtype and length. The decoder (#10202) bounds-checks the boundary values themselves. ## `BitPackedPatchedPlugin` The experimental-patches plugin declares both IDs as well. It moves a v2 array's interior patches into a `Patched` wrapper just as it does for v1, rebuilding the inner array with its block offsets instead of panicking on a blocked array. ## Editions and compressor `fastlanes.bitpacked.v2` is in no edition. Writers that enforce editions reject it, and readers that predate it report an unknown encoding. Nothing produces blocked arrays yet, so default writes don't change. `BitPackingScheme::produced_encodings` now declares `bitpacked_v1_id()`, since `BitPacked.id()` is the in-memory ID. --------- Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Tracking Issue: #10167
Summary
Adds support for decoding
BitPackedarrays with blocked bitwidths.Now each public function that decodes bitpacked arrays with global bitwidths has a version for blocked bitwidths.
unpack_array(array, ctx)unpack_array_blocked(array, offsets, ctx)unpack_primitive_arrayunpack_primitive_array_blockedunpack_into_primitive_builderunpack_into_primitive_builder_blockedunpack_single(array, index)unpack_single_blocked(array, offsets, index, ctx)Callers choose between them by matching on
bit_widths().There is no blocked
unpack_map_into_builder: its only caller, the wideningCastKernel, declines blocked arrays, so the mapped path would only run in tests.Design
#10004 only checks block boundary values in debug builds, so the decoder checks them itself:
u64and executes it once, checks that it holds one boundary per block plus a trailing one, and validates every boundary before writing to the builder. A single offset type keeps one copy of the block loop per value type, for 8 bytes per 1024 values. Each block must be a whole number of 128-byte rows, no wider than the array's type, and the boundaries must span the packed buffer.scalar_atreads only the selected block's boundaries, directly for host primitive offsets and throughexecute_scalarotherwise, and validates just that block.Both use
block_rangeinbitpacking/array/mod.rs, whichvalidate_primitive_offsetsnow also uses. Boundaries are relative to the first one, which may be nonzero.Full blocks unpack straight into the output, like the global decoder's full chunks. A partial first or last block unpacks into one 1024-value scratch block.